package org.fangzz.cameramgr.cameramonitor.service.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fangzz.cameramgr.cameramonitor.ApplicationConfig;
import org.fangzz.cameramgr.cameramonitor.dto.ResultCode;
import org.fangzz.cameramgr.cameramonitor.model.Camera;
import org.fangzz.cameramgr.cameramonitor.model.FfmpegProcess;
import org.fangzz.cameramgr.cameramonitor.model.MonitorType;
import org.fangzz.cameramgr.cameramonitor.model.Store;
import org.fangzz.cameramgr.cameramonitor.repository.CameraRepository;
import org.fangzz.cameramgr.cameramonitor.service.FfmpegProcessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.Collection;
import java.util.List;

/**
 * Created by cengruilin on 2018/6/7.
 */
@Service
public class FfmpegProcessServiceImpl implements FfmpegProcessService {

    private final static Log log = LogFactory.getLog(FfmpegProcessServiceImpl.class);

    @Autowired
    private StoreServiceImpl storeServiceImpl;

    @Autowired
    private CameraRepository cameraRepository;

    @Autowired
    private ApplicationConfig applicationConfig;

    @Override
    public FfmpegProcess startLiveConversion(Integer storeId, Integer id, String resolution) {
        Camera request = cameraRepository.findById(id).get();
        FfmpegProcess ffmpegProcess = new FfmpegProcess();
        if (request != null && request.isAlive()) {
            ffmpegProcess.setData(0);
            ffmpegProcess.setMonitorType(MonitorType.LIVE);
            ffmpegProcess.setPlayAddress(request.getLive());
            ffmpegProcess.setMsg("启动转码成功");
            return ffmpegProcess;
        }
        boolean isOutOfRunning = isOutOfRunning (storeId);
        if (isOutOfRunning){
            ffmpegProcess.setMsg("已达到最大上限!");
            ffmpegProcess.setData(1);
            return ffmpegProcess;
        }
        resolution = (resolution == null || "null".equals(resolution)) ? "720x640" : resolution;
        String command = String.format(applicationConfig.getLiveConversionCommand(), request.getRtspStreamAddress(), resolution, request.getRtmpStreamAddress());
        log.info("转码命令:" + command);
        try {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
            ffmpegProcess.setProcess(process);
            printMessage(process.getInputStream(), "标准流内容");
            printMessage(process.getErrorStream(), "错误流内容");
        } catch (Exception e) {
            log.error(String.format("命令启动失败: %s", command), e);
            throw new IllegalStateException("启动直播转码失败");
        }
        int usingAmount = request.getUsingAmount();
        request.setAlive(true);
        usingAmount += 1;    //使用人数加一
        request.setUsingAmount(usingAmount);
        cameraRepository.save(request);

        ffmpegProcess.setData(0);
        ffmpegProcess.setMonitorType(MonitorType.LIVE);
        ffmpegProcess.setPlayAddress(request.getLive());
        ffmpegProcess.setMsg("启动转码成功");
        return ffmpegProcess;
    }

    @Override
    public void exitLiveMonitor(Integer cameraId) {
        Camera camera = cameraRepository.findById(cameraId).get();
        int usingAmount = camera.getUsingAmount();
        usingAmount -= 1;
        if (usingAmount <= 0) {
            String rtspStreamAddress = camera.getRtspStreamAddress();
            String command = String.format(applicationConfig.getKillConversionCommand(), rtspStreamAddress);
            try {
                log.info("杀死进程命令：" + command);
                Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
                camera.setAlive(false);
                usingAmount = 0;
            } catch (Exception e) {
                log.error(String.format("命令启动失败: %s", command), e);
                throw new IllegalStateException("杀死进程失败");
            }
        } else {
            usingAmount -= 1;
        }
        camera.setUsingAmount(usingAmount);
        cameraRepository.save(camera);
    }

    @Override
    public FfmpegProcess startRecordConversion() {
        return null;
    }

    @Override
    public void killRecordConversion() {

    }

    @Override
    public boolean killFirstFfmpegProcess(Integer storeId) throws Exception {
        Store store = storeServiceImpl.findById(storeId);
        if (store == null) {
            throw new Exception();
        }
        List<Camera> cameraList = cameraRepository.findByStoreAndAndAlive(store, true);
        if (cameraList == null) {
            throw new Exception();
        }
        Camera camera = cameraList.get(0);
        if (camera.getLive() == null || camera.getLive().length() == 0) {
            throw new Exception();
        }
        String command = String.format(applicationConfig.getKillConversionCommand(), camera.getRtspStreamAddress());
        try {
            log.info("杀死进程命令：" + command);
            Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
        } catch (Exception e) {
            log.error(String.format("命令启动失败: %s", command), e);
            throw new IllegalStateException("杀死进程失败");
        }
        camera.setAlive(false);
        camera.setUsingAmount(0);
        cameraRepository.save(camera);
        return true;
    }

    @Override
    public ResultCode checkIsDeleted(Integer cameraId) {
        Camera camera = cameraRepository.findById(cameraId).get();
        if (camera != null) {
            if (camera.isAlive()){
                return ResultCode.result("转码进行中","0",true);
            }else{
                return ResultCode.result("转码进程已被杀死","0",false);
            }
        }
        return ResultCode.result("转码进程不存在","1",false);
    }

    @Override
    public int countOfRunning() {
        return 0;
    }

    @Override
    public Collection<FfmpegProcess> findAll() {
        return null;
    }

    @Override
    public String getLastOutput(String data) {
        return null;
    }

    private Boolean isOutOfRunning (Integer storeId) {
        Store store = storeServiceImpl.findById(storeId);
        if (store == null) {
            return true;
        }
        int maxRunning = store.getMaxTranscodeThread();
        List<Camera> cameraList = cameraRepository.findByStoreAndAndAlive(store, true);
        if (cameraList == null) {
            return true;
        }
        return maxRunning > cameraList.size() ? false : true;
    }

    private static void printMessage(final InputStream input, String msg) {
        new Thread(new Runnable() {
            public void run() {
                BufferedReader bf = new BufferedReader(new InputStreamReader(input));
                String line = null;
                try {
                    while ((line = bf.readLine()) != null) {
                        System.out.println("输出的" + msg + "为：" + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
